package netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HelloServer {
  public static void main(String[] args) {
    start();
  }

  public static void hello(){
    //1 启动器，负责组装netty组件，启动服务器
    new ServerBootstrap()
            //2 添加eventloop 组
            .group(new NioEventLoopGroup())
            //3 选择服务器的socketchannel实现
            .channel(NioServerSocketChannel.class)
            //4 work执行逻辑
            .childHandler(
                    //5 channel 代表和客户端数据读写的通道
                    new ChannelInitializer<NioSocketChannel>() {
                      @Override
                      protected void initChannel(NioSocketChannel channel) throws Exception {
                        //6 具体handler
                        channel.pipeline().addLast(new StringDecoder()); // 将ByteBuffer 转换为字符串
                        channel.pipeline().addLast(new ChannelInboundHandlerAdapter() { // 自定义handler
                          @Override
                          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            System.out.println(msg);
                          }
                        });
                      }
                    })
            //7 绑定监听端口
            .bind(8099);
  }

  public static void start(){
    NioEventLoopGroup boss = new NioEventLoopGroup();
    NioEventLoopGroup worker = new NioEventLoopGroup();
    try {
      ServerBootstrap sbt = new ServerBootstrap();
      //调整的是系统的接口缓冲区（滑动窗口）
//      sbt.option(ChannelOption.SO_RCVBUF,10);
      // 调整 netty 的接受缓冲区
//      sbt.childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(16,16,16));
      sbt.channel(NioServerSocketChannel.class);
      sbt.group(boss,worker);
      sbt.childHandler(new ChannelInitializer<NioSocketChannel>() {
        @Override
        protected void initChannel(NioSocketChannel ch) throws Exception {
//          ch.pipeline().addLast(new FixedLengthFrameDecoder(10));
//          ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
//          ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,0,4,1,4));
          ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
          ch.pipeline().addLast(new HttpServerCodec());
          // http请求进入之后，虽然只是一次请求但是会拆分两部分触发两次 read handler
          ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
              log.debug("{}",msg.getClass());
              //HttpRequest 包含请求头信息
              if (msg instanceof HttpRequest){
                log.debug("request header:{}",msg);
              //HttpContent 包含请求体信息，get请求也会有，但是内容是空的
              }else if (msg instanceof HttpContent){
                log.debug("request content:{}",msg);
              }
              super.channelRead(ctx, msg);
            }
          });
          ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpRequest>() {
            @Override
            protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
              log.debug("###################################################");
              log.debug("###################################################");
              log.debug("SimpleChannelInboundHandler request header:{}",msg);
              log.debug("uri:{}",msg.uri());

              DefaultFullHttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK);
              byte[] bytes = "<h1>request rabbit</h1>".getBytes();
              response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH,bytes.length);
              response.content().writeBytes(bytes);
              ctx.writeAndFlush(response);
              log.debug("###################################################");
              log.debug("###################################################");

            }
          });
        }
      });
      ChannelFuture future = sbt.bind(8080);
      future.channel().closeFuture().sync();
    }catch (Exception e){
      log.error("server error");
      e.printStackTrace();
    }finally {
      boss.shutdownGracefully();
      worker.shutdownGracefully();
    }
  }

  public static void start1(){
    NioEventLoopGroup boss = new NioEventLoopGroup(1);
    NioEventLoopGroup worker = new NioEventLoopGroup();
    try {
      ServerBootstrap serverBootstrap = new ServerBootstrap();
      serverBootstrap.channel(NioServerSocketChannel.class);
      // 调整channel的容量
      serverBootstrap.option(ChannelOption.SO_RCVBUF, 10);
      serverBootstrap.group(boss, worker);
      serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
        @Override
        protected void initChannel(SocketChannel ch) {
          ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
          ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {
              // 连接建立时会执行该方法
              log.debug("connected {}", ctx.channel());
              super.channelActive(ctx);
            }

            @Override
            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
              // 连接断开时会执行该方法
              log.debug("disconnect {}", ctx.channel());
              super.channelInactive(ctx);
            }
          });
        }
      });
      ChannelFuture channelFuture = serverBootstrap.bind(8080);
      log.debug("{} binding...", channelFuture.channel());
      channelFuture.sync();
      log.debug("{} bound...", channelFuture.channel());
      // 关闭channel
      channelFuture.channel().closeFuture().sync();
    } catch (InterruptedException e) {
      log.error("server error", e);
    } finally {
      boss.shutdownGracefully();
      worker.shutdownGracefully();
      log.debug("stopped");
    }
  }
}
